#include "Application.hpp"

Application::Application() : myStatusCode(sl::StatusCode::Init), myErrorCode(sl::ErrorCode::NothingSpecific), myIsPaused(false)
{}

Application::~Application()
{}

sl::StatusCode Application::Init()
{
	*sl::LogManager->Get("application")->Write("Enter Init");
	*sl::LogManager->Get("application")->Write("\tTry to create the window");

	if (sl::RenderScreen->LoadFromFile(sl::LoadFromFile("Settings/window.xml")) == NULL)
		sl::RenderScreen->Create(sf::VideoMode(800, 600, 32), "Caption", sf::Style::Close, sf::ContextSettings());

	if (!sl::RenderScreen->Open())
	{
		myErrorCode = sl::ErrorCode::OpenWindow;
		sl::Exception("Can't create a Window", myErrorCode);
		return myStatusCode = sl::StatusCode::Quit;
	}

	sl::RenderScreen->SetFramerate(60);
	//(*sl::RenderScreen)()->EnableKeyRepeat(false);

	*sl::LogManager->Get("application")->Write("\tWindow created");

	sl::ScriptManager->Start("init");

	sl::RenderTextureManager->SetActive(false);
	if (sl::RenderTextureManager->IsActive())
	{
		sl::RenderTextureManager->Create("screen");
		sl::RenderTextureManager->Create("map");
	
		for (unsigned int i = 0; i < 7; i++)
			sl::RenderTextureManager->Create("layer" + sl::Convert(i));

		sl::RenderTextureManager->Create("anim");
		sl::RenderTextureManager->Create("gui");
	}
	
	sl::TextureManager->LoadFromFile(*sl::FolderManager->Get("image") + "character.png", sf::Color::Black, "hero");

	sl::ScriptManager->Start("anim");

	sl::AnimationManager->Insert("hero", new sl::Animation(sl::TextureManager->Get("hero"), sf::Vector2i(4, 4)))
		->AddFrame(0, 15)->AddFrame(1, 15)->AddFrame(2, 15)->AddFrame(3, 15)
		->AddFrame(4, 15)->AddFrame(5, 15)->AddFrame(6, 15)->AddFrame(7, 15)
		->AddFrame(8, 15)->AddFrame(9, 15)->AddFrame(10, 15)->AddFrame(11, 15)
		->AddFrame(12, 15)->AddFrame(13, 15)->AddFrame(14, 15)->AddFrame(15, 15)
		->Start();

	sl::DirAnimation* hero2 = new sl::DirAnimation(sl::Animation(sl::TextureManager->Get("hero"), sf::Vector2i(4, 4)));
	hero2
		->AddFrame(0, 15)->AddFrame(1, 15)->AddFrame(2, 15)->AddFrame(3, 15)
		->SetDirection(sl::Direction::Right)
		->AddFrame(4, 15)->AddFrame(5, 15)->AddFrame(6, 15)->AddFrame(7, 15)
		->SetDirection(sl::Direction::Down)
		->AddFrame(8, 15)->AddFrame(9, 15)->AddFrame(10, 15)->AddFrame(11, 15)
		->SetDirection(sl::Direction::Left)
		->AddFrame(12, 15)->AddFrame(13, 15)->AddFrame(14, 15)->AddFrame(15, 15)
		->SetDirection(sl::Direction::Up);
	sl::DirAnimationManager->Insert("hero", hero2)
		->Start()->SetPosition(250, 250);		

	sl::TileMap->Load(*sl::FolderManager->Get("map") + /*trees.tmx");/*/"iso.tmx");

	sf::Shader shader_multiply;
	shader_multiply.LoadFromFile(*sl::FolderManager->Get("shader") + /*"additional.glsl");/*/"multiply.glsl");
	sl::ShaderManager->Insert("multiply", shader_multiply);
	
	*sl::LogManager->Get("application")->Write("Exit Init");
	return myStatusCode = sl::StatusCode::Event;
}

sl::StatusCode Application::Update(float time)
{
	time /= 1000;
	time += 0.00085f;
	sl::AnimationManager->Update(time);
	sl::DirAnimationManager->Update(time);
	return myStatusCode = sl::StatusCode::Draw;
}

sl::StatusCode Application::Draw()
{
	(*sl::RenderScreen)()->Clear(sf::Color::White);
	sl::RenderTextureManager->Clear();

	sl::ScriptManager->Start("test");

	sl::TileMap->Draw("Base");

	sl::AnimationManager->Draw(sl::RenderTextureManager->Get("anim"));
	sl::DirAnimationManager->Draw(sl::RenderTextureManager->Get("diranim"));

	for (unsigned int i = 0; i < 2; i++)
		sl::TileMap->Draw("Objects" + sl::Convert(i));
	
	sl::RenderTextureManager->Display();
	
	sl::RenderTextureManager->Draw("layer0");
	sl::RenderTextureManager->Draw("anim");
	sl::RenderTextureManager->Draw("diranim");
	sl::RenderTextureManager->Draw("layer1");
	sl::RenderTextureManager->Draw("gui");

	if (sl::RenderTextureManager->Get("diranim") != NULL)
	{
		sl::DirAnimationManager->Draw(sl::RenderTextureManager->Get("diranim"), *sl::ShaderManager->Get("multiply"));
		sl::RenderTextureManager->Draw("diranim");
	}

	sl::RenderTextureManager->Draw("screen");
	(*sl::RenderScreen)()->Display();

	return myStatusCode = sl::StatusCode::Event;
}

sl::StatusCode Application::Event()
{
	if ((*sl::RenderScreen)()->IsOpened())
	{
		sf::Event event;
		while ((*sl::RenderScreen)()->PollEvent(event))
		{
			// Window 
			switch (event.Type)
			{
			case sf::Event::Closed:
				return myStatusCode = sl::StatusCode::Quit;
				break;
			case sf::Event::LostFocus:
				return myStatusCode = sl::StatusCode::Pause;
				break;
			case sf::Event::GainedFocus:
				return myStatusCode = sl::StatusCode::Event;
				break;
			}

			switch (event.Key.Code)
			{
			case sf::Keyboard::Key::Escape:
				return myStatusCode = sl::StatusCode::Quit;
				break;
			case sf::Keyboard::Key::P:
				myIsPaused = !myIsPaused;
				break;
			}

//#ifdef _DEBUG
			if (event.Key.Shift && event.Key.Code == sf::Keyboard::Key::D)
				DebugInput();
//#endif
		}
	}

	if (!myIsPaused)
	{
		myStatusCode = sl::StatusCode::Update;
		sl::ScriptManager->Start("input");
	}
	else
	{
		myStatusCode = sl::StatusCode::Pause;
	}

	return myStatusCode;
}

sl::StatusCode Application::DebugInput()
{
	std::string input;
	std::cout << "Enter Lua command line" << std::endl;
	do
	{
		std::cout << "> ";
		std::getline(std::cin, input);
		if (input != "")
			sl::Lua->Execute(input);
	} while (input != "");

	std::cout << "Exit Lua command line" << std::endl;
	return myStatusCode;
}

sl::StatusCode Application::Pause()
{
	(*sl::RenderScreen)()->Clear(sf::Color::White);
	sf::Text text;
	text.SetString("Pause");
	text.SetFont(sf::Font::GetDefaultFont());
	text.SetCharacterSize((*sl::RenderScreen)()->GetHeight() / 5);
	sf::FloatRect rect(text.GetRect());
	text.SetPosition((*sl::RenderScreen)()->GetWidth() / 2 - rect.Width / 2, (*sl::RenderScreen)()->GetHeight() / 2 - rect.Height);
	text.SetColor(sf::Color(155, 200, 200));
	(*sl::RenderScreen)()->Draw(text);

	(*sl::RenderScreen)()->Display();

	return myStatusCode = sl::StatusCode::Event;
}

sl::StatusCode Application::Quit()
{
	*sl::LogManager->Get("application")->Write("Enter Quit");
		
	(*sl::RenderScreen)()->Close();

	sl::ScriptManager->Start("quit");
	sl::Lua->Close();

	*sl::LogManager->Get("application")->Write("Exit Quit");
	return myStatusCode = sl::StatusCode::End;
}

unsigned short Application::GetErrorCode()
{
	return myErrorCode;
}

sl::ErrorCode Application::operator()()
{
	while (myStatusCode != sl::StatusCode::End)
		switch (myStatusCode)
		{
		case sl::StatusCode::Init:
			Init();
			break;
		case sl::StatusCode::Event:
			Event();
			break;
		case sl::StatusCode::Update:
			Update((*sl::RenderScreen)()->GetFrameTime());
			break;
		case sl::StatusCode::Draw:
			Draw();
			break;
		case sl::StatusCode::Pause:
			Pause();
			break;
		case sl::StatusCode::Quit:
			Quit();
			break;
		}

	return myErrorCode;
}